package com.auto.api.core.type.marge;

import com.auto.api.core.constants.MappingConstants;
import com.auto.api.core.entity.BeanMargeContext;
import com.auto.api.core.entity.ProcessProp;
import com.auto.api.core.entity.PropertyContext;
import com.auto.api.core.type.TypeFactory;
import com.auto.api.core.util.BeanUtil;
import java.beans.PropertyDescriptor;
import java.util.Collection;
import java.util.Objects;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.ResolvableType;

/**
 * @program:
 * @description: Bean Marge业务实现
 * @author: liangshf
 * @create: 2020-09-24
 */
public class BeanMargeHandlerImpl extends AbstractBeanMargeHandler {

    @Override
    public ProcessProp<BeanMargeContext> getProcessProp(BeanMargeContext context, PropertyContext propertyContext) {
        return new ProcessProp(propertyContext.getJudgePropType(), context, propertyContext);
    }

    @Override
    public void processProp(ProcessProp<BeanMargeContext> processProp) {
        PropertyDescriptor prop = processProp.getPropertyContext().getProp();
        //多个继承泛型替换
        if (TypeFactory.isSimpleTypeHandler(processProp.getPropType())) {
            if (processProp.getPropertyContext().isCollectionType()) {
                margeCollection(processProp.getContext(), processProp.getPropertyContext());
                return;
            }
            margeProp(processProp.getContext(), prop);
        } else {
            if (processProp.getPropertyContext().isCollectionType()) {
                margeCollection(processProp.getContext(), processProp.getPropertyContext());
                return;
            }
            margeObj(processProp.getContext(), prop);
        }
    }

    private void margeObj(BeanMargeContext beanMargeContext, PropertyDescriptor prop) {
        try {
            beanMargeContext.setResult(
                getResult(new BeanMargeContext(
                        PropertyUtils.getSimpleProperty(beanMargeContext.getResult(), prop.getName())
                        , PropertyUtils.getSimpleProperty(beanMargeContext.getMargeObj(), prop.getName())
                    )
                )
            );
        } catch (Exception ex) {
            logger.info("data marge error !!", ex);
        }
    }

    private void margeProp(BeanMargeContext beanMargeContext, PropertyDescriptor prop) {
        // Only copy writable attributes
        try {
            if (prop.getWriteMethod() != null && beanMargeContext.isHasBeanMarge() && beanMargeContext.isDataMarge()) {
                Object margeValue =  PropertyUtils.getSimpleProperty(beanMargeContext.getMargeObj(), prop.getName());
                if (Objects.nonNull(margeValue)) {
                    PropertyUtils.setSimpleProperty(beanMargeContext.getResult(), prop.getName(), margeValue);
                }
            }
        } catch (Exception ex) {
            logger.info("data marge error !!", ex);
        }
    }

    private void margeCollection(BeanMargeContext beanMargeContext, PropertyContext propertyContext) {
        try {
            PropertyDescriptor prop = propertyContext.getProp();
            Collection<Object> margeCollection =  (Collection<Object>) PropertyUtils
                .getSimpleProperty(beanMargeContext.getMargeObj(), prop.getName());
            Collection<Object> results = (Collection<Object>)PropertyUtils.getSimpleProperty(beanMargeContext.getResult(), prop.getName());
            ResolvableType fieldType = propertyContext.getPropResType();
            margeCollection.forEach(margeData -> {
                for(int i=0 ; i < fieldType.getGenerics().length ; i++) {
                    ResolvableType fieldGenType = fieldType.getGenerics()[i];
                    String typeName = fieldType.resolve().getSimpleName();
                    if (MappingConstants.CLASS.equals(BeanUtil.captureName(typeName)) || fieldGenType.resolve().getSimpleName().equals(beanMargeContext.getSimpleClassName())) {
                        return;
                    }
                    //参数类型
                    if (TypeFactory.isSimpleTypeHandler(typeName)) {
                        margeProp(beanMargeContext, prop);
                    } else {
                        //泛型类对应泛型属性
                    Class clazz = typeName.length() <= 1 && StringUtils.isNotEmpty(fieldGenType.resolve().getName())
                        ? BeanUtil.getClass(fieldGenType.resolve().getName()): BeanUtil.getClass(margeData.getClass().getTypeName());
                    if (clazz == null) return;
                        results.forEach(result -> beanMargeContext.setResult(getResult(new BeanMargeContext(result, margeData))));
                    }
                }
            });
        } catch (Exception ex) {
            logger.info("data marge error !!", ex);
        }
    }
}
